let resWrite = require('./response');
let resNotModified = require('./response_not_modified');
const path = require('path');
const fs = require('fs');

/**
 * response a file
 * @param {object} args
 * @param {Function} callback
 */
function resFile(args, callback) {
  let response = args.response;
  let statusCode = args.statusCode;
  let cookies = args.cookies || null;
  let encoding = args.encoding;
  let cache = args.cache;
  let realPath = args.realPath;
  let ifModifiedSince = args.ifModifiedSince;
  let mimeKey = path.extname(realPath).toLocaleLowerCase();
  mimeKey = mimeKey ? mimeKey.slice(1) : "";
  new Promise((resolve, reject) => {
    response ? resolve() : reject();
  }).then(
      () => {
        new Promise((resolve, reject) => {
          cache ? resolve() : reject();
        }).then(
            //use cache
            () => {
              new Promise((resolve, reject) => {
                ifModifiedSince === undefined ? resolve() : reject();
              }).then(
                  //no if-Modified-Since Header
                  () => {
                    fs.stat(realPath, (err, stats) => {
                      new Promise((resolve, reject) => {
                        !err ? resolve() : reject();
                      }).then(
                          //success
                          () => {
                            ifModifiedSince = stats.mtime;
                            new Promise((resolve, reject) => {
                              encoding ? resolve() : reject();
                            }).then(
                                //use encoding
                                () => {
                                  new Promise((resolve, reject) => {
                                    cookies ? resolve() : reject();
                                  }).then(
                                      //use cookie
                                      () => {
                                        new Promise((resolve, reject) => {
                                          resWrite({
                                            response: response,
                                            statusCode: statusCode,
                                            mimeKey: mimeKey,
                                            dataType: 'stream',
                                            stream: fs.createReadStream(realPath),
                                            encoding: encoding,
                                            cookies: cookies,
                                            cache: true,
                                            lastModified: ifModifiedSince
                                          }, (error, statusCode) => {
                                            !error ? resolve(statusCode) : reject(error);
                                          })
                                        }).then(
                                            //success
                                            (statusCode) => {
                                              callback(null, statusCode);
                                            }
                                            //error
                                            , (error) => {
                                              callback(error, null);
                                            }
                                        ).catch((error) => {
                                          callback(error, null);
                                        })
                                      }
                                      //not use cookie
                                      , () => {
                                        new Promise((resolve, reject) => {
                                          resWrite({
                                            response: response,
                                            statusCode: statusCode,
                                            mimeKey: mimeKey,
                                            dataType: 'stream',
                                            stream: fs.createReadStream(realPath),
                                            encoding: encoding,
                                            cache: true,
                                            lastModified: ifModifiedSince
                                          }, (error, statusCode) => {
                                            !error ? resolve(statusCode) : reject(error);
                                          })
                                        }).then(
                                            //success
                                            (statusCode) => {
                                              callback(null, statusCode);
                                            }
                                            //error
                                            , (error) => {
                                              callback(error, null);
                                            }
                                        ).catch((error) => {
                                          callback(error, null);
                                        })
                                      }
                                  ).catch((error) => {
                                    callback(error, null);
                                  })
                                }
                                //not use encoding
                                , () => {
                                  new Promise((resolve, reject) => {
                                    cookies ? resolve() : reject();
                                  }).then(
                                      //use cookie
                                      () => {
                                        new Promise((resolve, reject) => {
                                          resWrite({
                                            response: response,
                                            statusCode: statusCode,
                                            mimeKey: mimeKey,
                                            dataType: 'stream',
                                            stream: fs.createReadStream(realPath),
                                            cookies: cookies,
                                            cache: true,
                                            lastModified: ifModifiedSince
                                          }, (error, statusCode) => {
                                            !error ? resolve(statusCode) : reject(error);
                                          })
                                        }).then(
                                            //success
                                            (statusCode) => {
                                              callback(null, statusCode);
                                            }
                                            //error
                                            , (error) => {
                                              callback(error, null);
                                            }
                                        ).catch((error) => {
                                          callback(error, null);
                                        })
                                      }
                                      //not use cookie
                                      , () => {
                                        new Promise((resolve, reject) => {
                                          resWrite({
                                            response: response,
                                            statusCode: statusCode,
                                            mimeKey: mimeKey,
                                            dataType: 'stream',
                                            stream: fs.createReadStream(realPath),
                                            cache: true,
                                            lastModified: ifModifiedSince
                                          }, (error, statusCode) => {
                                            !error ? resolve(statusCode) : reject(error);
                                          })
                                        }).then(
                                            //success
                                            (statusCode) => {
                                              callback(null, statusCode);
                                            }
                                            //error
                                            , (error) => {
                                              callback(error, null);
                                            }
                                        ).catch((error) => {
                                          callback(error, null);
                                        })
                                      }
                                  ).catch((error) => {
                                    callback(error, null);
                                  })
                                }
                            ).catch((error) => {
                              callback(error, null);
                            })
                          }
                          //path error
                          , () => {
                            callback(new SyntaxError('path error'), null);
                          }
                      ).catch((error) => {
                        callback(error, null);
                      })
                    })
                  }
                  //hava if-Modified-Since Header
                  , () => {
                    fs.stat(realPath, (error, stats) => {
                      new Promise((resolve, reject) => {
                        !error ? resolve(stats) : reject(error);
                      }).then(
                          //success
                          () => {
                            new Promise((resolve, reject) => {
                              new Date(ifModifiedSince).toUTCString() === new Date(stats.mtime).toUTCString() ? resolve() : reject();
                            }).then(
                                //success
                                () => {
                                  resNotModified({response: response}, (error, statusCode) => {
                                    new Promise((resolve,reject)=>{
                                      !error ? resolve(statusCode) : reject(error);
                                    }).then(
                                        //sucess
                                        (statusCode) => {
                                          callback(null, statusCode);
                                        }
                                        //fail
                                        , (error) => {
                                          callback(error, null);
                                        }
                                    ).catch((error)=>{
                                      callback(error,null);
                                    })
                                  })
                                }
                                //fail
                                , () => {
                                  ifModifiedSince = stats.mtime;
                                  new Promise((resolve, reject) => {
                                    encoding ? resolve() : reject();
                                  }).then(
                                      //use encoding
                                      () => {
                                        new Promise((resolve, reject) => {
                                          cookies ? resolve() : reject();
                                        }).then(
                                            //use cookie
                                            () => {
                                              new Promise((resolve, reject) => {
                                                resWrite({
                                                  response: response,
                                                  statusCode: statusCode,
                                                  mimeKey: mimeKey,
                                                  dataType: 'stream',
                                                  stream: fs.createReadStream(realPath),
                                                  encoding: encoding,
                                                  cookies: cookies,
                                                  cache: true,
                                                  lastModified: ifModifiedSince
                                                }, (error, statusCode) => {
                                                  !error ? resolve(statusCode) : reject(error);
                                                })
                                              }).then(
                                                  //success
                                                  (statusCode) => {
                                                    callback(null, statusCode);
                                                  }
                                                  //error
                                                  , (error) => {
                                                    callback(error, null);
                                                  }
                                              ).catch((error) => {
                                                callback(error, null);
                                              })
                                            }
                                            //not use cookie
                                            , () => {
                                              new Promise((resolve, reject) => {
                                                resWrite({
                                                  response: response,
                                                  statusCode: statusCode,
                                                  mimeKey: mimeKey,
                                                  dataType: 'stream',
                                                  stream: fs.createReadStream(realPath),
                                                  encoding: encoding,
                                                  cache: true,
                                                  lastModified: ifModifiedSince
                                                }, (error, statusCode) => {
                                                  !error ? resolve(statusCode) : reject(error);
                                                })
                                              }).then(
                                                  //success
                                                  (statusCode) => {
                                                    callback(null, statusCode);
                                                  }
                                                  //error
                                                  , (error) => {
                                                    callback(error, null);
                                                  }
                                              ).catch((error) => {
                                                callback(error, null);
                                              })
                                            }
                                        ).catch((error) => {
                                          callback(error, null);
                                        })
                                      }
                                      //not use encoding
                                      , () => {
                                        new Promise((resolve, reject) => {
                                          cookies ? resolve() : reject();
                                        }).then(
                                            //use cookie
                                            () => {
                                              new Promise((resolve, reject) => {
                                                resWrite({
                                                  response: response,
                                                  statusCode: statusCode,
                                                  mimeKey: mimeKey,
                                                  dataType: 'stream',
                                                  stream: fs.createReadStream(realPath),
                                                  cookies: cookies,
                                                  cache: true,
                                                  lastModified: ifModifiedSince
                                                }, (error, statusCode) => {
                                                  !error ? resolve(statusCode) : reject(error);
                                                })
                                              }).then(
                                                  //success
                                                  (statusCode) => {
                                                    callback(null, statusCode);
                                                  }
                                                  //error
                                                  , (error) => {
                                                    callback(error, null);
                                                  }
                                              ).catch((error) => {
                                                callback(error, null);
                                              })
                                            }
                                            //not use cookie
                                            , () => {
                                              new Promise((resolve, reject) => {
                                                resWrite({
                                                  response: response,
                                                  statusCode: statusCode,
                                                  mimeKey: mimeKey,
                                                  dataType: 'stream',
                                                  stream: fs.createReadStream(realPath),
                                                  cache: true,
                                                  lastModified: ifModifiedSince
                                                }, (error, statusCode) => {
                                                  !error ? resolve(statusCode) : reject(error);
                                                })
                                              }).then(
                                                  //success
                                                  (statusCode) => {
                                                    callback(null, statusCode);
                                                  }
                                                  //error
                                                  , (error) => {
                                                    callback(error, null);
                                                  }
                                              ).catch((error) => {
                                                callback(error, null);
                                              })
                                            }
                                        ).catch((error) => {
                                          callback(error, null);
                                        })
                                      }
                                  ).catch((error) => {
                                    callback(error, null);
                                  })
                                }
                            ).catch((error) => {
                              callback(error, null);
                            })
                          }
                          //path error
                          , (error) => {
                            callback(new SyntaxError('path error'), null);
                          }
                      ).catch((error) => {
                        callback(error, null);
                      })
                    })
                  }
              ).catch((error) => {
                callback(error, null);
              })
            }
            //not use cache
            , () => {
              new Promise((resolve, reject) => {
                encoding ? resolve() : reject();
              }).then(
                  //use encoding
                  () => {
                    new Promise((resolve, reject) => {
                      cookies ? resolve() : reject();
                    }).then(
                        //use cookie
                        () => {
                          new Promise((resolve, reject) => {
                            resWrite({
                              response: response,
                              statusCode: statusCode,
                              mimeKey: mimeKey,
                              dataType: 'stream',
                              stream: fs.createReadStream(realPath),
                              encoding: encoding,
                              cookies: cookies,
                            }, (error, statusCode) => {
                              !error ? resolve(statusCode) : reject(error);
                            })
                          }).then(
                              //success
                              (statusCode) => {
                                callback(null, statusCode);
                              }
                              //error
                              , (error) => {
                                callback(error, null);
                              }
                          ).catch((error) => {
                            callback(error, null);
                          })
                        }
                        //not use cookie
                        , () => {
                          new Promise((resolve, reject) => {
                            resWrite({
                              response: response,
                              statusCode: statusCode,
                              mimeKey: mimeKey,
                              dataType: 'stream',
                              stream: fs.createReadStream(realPath),
                              encoding: encoding,
                            }, (error, statusCode) => {
                              !error ? resolve(statusCode) : reject(error);
                            })
                          }).then(
                              //success
                              (statusCode) => {
                                callback(null, statusCode);
                              }
                              //error
                              , (error) => {
                                callback(error, null);
                              }
                          ).catch((error) => {
                            callback(error, null);
                          })
                        }
                    ).catch((error) => {
                      callback(error, null);
                    })
                  }
                  //not use encoding
                  , () => {
                    new Promise((resolve, reject) => {
                      cookies ? resolve() : reject();
                    }).then(
                        //use cookie
                        () => {
                          new Promise((resolve, reject) => {
                            resWrite({
                              response: response,
                              statusCode: statusCode,
                              mimeKey: mimeKey,
                              dataType: 'stream',
                              stream: fs.createReadStream(realPath),
                              cookies: cookies,
                            }, (error, statusCode) => {
                              !error ? resolve(statusCode) : reject(error);
                            })
                          }).then(
                              //success
                              (statusCode) => {
                                callback(null, statusCode);
                              }
                              //error
                              , (error) => {
                                callback(error, null);
                              }
                          ).catch((error) => {
                            callback(error, null);
                          })
                        }
                        //not use cookie
                        , () => {
                          new Promise((resolve, reject) => {
                            resWrite({
                              response: response,
                              statusCode: statusCode,
                              mimeKey: mimeKey,
                              dataType: 'stream',
                              stream: fs.createReadStream(realPath),
                            }, (error, statusCode) => {
                              !error ? resolve(statusCode) : reject(error);
                            })
                          }).then(
                              //success
                              (statusCode) => {
                                callback(null, statusCode);
                              }
                              //error
                              , (error) => {
                                callback(error, null);
                              }
                          ).catch((error) => {
                            callback(error, null);
                          })
                        }
                    ).catch((error) => {
                      callback(error, null);
                    })
                  }
              ).catch((error) => {
                callback(error, null);
              })
            }
        ).catch((error) => {
          callback(error, null);
        })
      }
      , () => {
        callback(new SyntaxError("response can't be undefined"), null);
      }
  ).catch((error) => {
    callback(error, null);
  })
}

module.exports = resFile;